#include <QDebug>

#include <iostream>
#include <fstream>

#include "Field.h"
#include "Graphics.h"
#include "Mob.h"
#include "Bullet.h"
#include "BlackHole.h"
#include "PriorityQueue.h"

#include "RoamingGangster.h"
#include "KeyboardController.h"
#include "FollowerGangster.h"
#include "WaypointGangster.h"

using namespace std;

void Field::update() {
    QTime time;
    time.start();

    ++currentUpdate;
    if( currentUpdate > HEIGHT*WIDTH ) currentUpdate = 1;
    PriorityQueue<Object*> queue;
    for( int i = 0; i < WIDTH; i++ ){
        for( int j = 0; j < HEIGHT; j++ ){
             queue.insert( field[i][j] );
        }
    }  

    for( int i = 0; i < WIDTH; i++ ){
        for( int j = 0; j < HEIGHT; j++ ){
            if( queue.max() ) { queue.extractMax()->update( currentUpdate ); }
            else { break; }
             //if( field[i][j] ) field[i][j]->update( currentUpdate );
             //else graph->paint( i, j, 0 );
        }
    }

    graph->paintAll();

    shop->addMoney( 1 );
    qDebug() << time.elapsed();
}

void Field::addDeath( Team team ){
    switch( team ){
        case( TEAMENUM ) : deathsOfGreen++; break;
        case( TEAMID )   :   deathsOfRed++; break;
        case( TEAMDEMON ): deathsOfDemons++;break;
    }
}

void Field::saveInFile( const char* name, const char* name2 ) {
    ofstream save, config;
    save.open( name );
    config.open( name2 );
    if( !save.is_open() ) {
        return;
    }
    if( !config.is_open() ) {
        return;
    }
    for( int i = 0; i < HEIGHT; i++ ) {
        for( int j = 0; j < WIDTH ; j++ ) {
            if( field[j][i] ) field[j][i]->save( &save, &config );
            else save << EMPTYSPACE;
        }
        save << endl;
    }

    config << deathsOfGreen << endl << deathsOfRed << endl
            << deathsOfRed << endl << shop->getMoney() << endl;

    QTime time;
    QDate date;
    time = time.currentTime();
    date = date.currentDate();
    config << "SAVE TIME:"  << date.day() << "." << date.month() << "."
           << date.year() << ":" << time.hour() << "."  << time.minute() << "."
           << time.second() << "." << time.msec() << endl
           << "Field size:" << Field::WIDTH << "x" << Field::HEIGHT;
    save.close();
    config.close();
}

void Field::loadFromFile( const char* name, const char* name2 ) {
    qDebug() << "It lives";
    ifstream save, config;
    save.open( name );
    config.open( name2 );
    if( !save.is_open() ) {
        qDebug() << "STREAM BREAK";
        return;
    }
    if( !config.is_open() ) {
        qDebug() << "STREAM BREAK";
        return;
    }
    char c;
    string line;
    int lifes, speed, cooldown, currentCd, spawnRate, shifts;
    int xp = 0, targetXp = 0, level = 0,
        timedLife = 0, timeTillDeath = 1,
        sightRange = 0;
    Direction d;
    bool hasPlayer = false;
    for( int i = 0; i < HEIGHT; i++ ) {
        for( int j = 0; j < WIDTH; j++ ) {
            save >> c;
            if( field[j][i] ) delete field[j][i];
            switch( c ) {
                case( EMPTYSPACE ):
                    field[j][i] = 0;
                    break;
                case( Wall::WALLCHAR ):
                    field[j][i] = new Wall( j, i, this, true );
                    break;
                case( Gangster::GANGSTERCHAR ):
                config >> c;
                    if( c != 'G' ) {
                        qDebug() << "GANGSTER BREAK";
                        field[j][i] = 0;
                        return;
                    }

                    getline( config, line );
                    lifes = atoi( line.c_str() );

                    config >> c;
                    Team team;
                    switch( c ) {
                        case( TEAMENUMCHAR ):  team = TEAMENUM;  break;
                        case( TEAMIDCHAR ):    team = TEAMID;    break;
                        case( TEAMDEMONCHAR ): team = TEAMDEMON; break;
                        default:               team = TEAMENUM;  break;
                    }

                    getline( config, line );
                    speed = atoi( line.c_str() );

                    config >> c;
                    Controller* control;
                    bool player;
                    switch( c ) {
                        case( RoamingGangster::ROAMINGGANGSTERCHAR ):
                            control = new RoamingGangster( 0, NONE, 0 );
                            player = false;
                            break;
                        case( FollowerGangster::FOLLOWERGANGSTERCHAR ):
                            control = new FollowerGangster();
                            player = false;
                            break;
                        case( WaypointGangster::WAYPOINTGANGSTERCHAR ):
                            control = new WaypointGangster();
                            player = false;
                            break;
                        case( KeyboardController::KEYBOARDCONTROLLERCHAR ):
                            control = new KeyboardController( 0, graph->playerInput() );
                            player = true;
                            hasPlayer = true;
                            break;
                        default:
                            control = new RoamingGangster( 0, NONE, 0 );
                            player = false;
                            break;
                    }

                    getline( config, line );
                    shifts = atoi( line.c_str() );

                    getline( config, line );
                    xp = atoi( line.c_str() );

                    getline( config, line );
                    targetXp = atoi( line.c_str() );

                    getline( config, line );
                    level = atoi( line.c_str() );

                    getline( config, line );
                    timedLife = atoi( line.c_str() );

                    getline( config, line );
                    timeTillDeath = atoi( line.c_str() );

                    getline( config, line );
                    sightRange = atoi( line.c_str() );

                    field[j][i] = new Gangster( j, i, this, true, team, control, speed, lifes, false, player,
                                                timedLife, timeTillDeath, shifts, 1, xp, sightRange, level );
                    if( player == true ) {
                        this->player = dynamic_cast<Mob*>( field[j][i] );
                    }
                    break;
                case( Bullet::BULLETCHAR ):
                    config >> c;
                    if( c != 'B' ) {
                        qDebug() <<"BULLET BREAK";
                        field[j][i] = 0;
                        return;
                    }
                    getline( config, line );
                    d = Direction( atoi( line.c_str() ) );

                    getline( config, line );
                    speed = atoi( line.c_str() );

                    field[j][i] = new Bullet( j, i, this, true, d, speed );
                    break;
                case( BlackHole::BLACKHOLECHAR ):
                    config >> c;
                    if( c != BlackHole::BLACKHOLECHAR ) {
                        qDebug() << "HOLE BREAK";
                        field[j][i] = 0;
                        return;
                    }
                    getline( config, line );
                    cooldown = atoi( line.c_str() );

                    getline( config, line );
                    spawnRate = atoi( line.c_str() );

                    getline( config, line );
                    currentCd = atoi( line.c_str() );

                    getline( config, line );
                    lifes = atoi( line.c_str() );

                    config >> c;
                    switch( c ) {
                        case( TEAMENUMCHAR ):  team = TEAMENUM;  break;
                        case( TEAMIDCHAR ):    team = TEAMID;    break;
                        case( TEAMDEMONCHAR ): team = TEAMDEMON; break;
                        default:               team = TEAMENUM;  break;
                    }

                    field[j][i] = new BlackHole( j, i, this, true, spawnRate,
                                                 cooldown, lifes, currentCd,
                                                 team );
                    break;
                default:
                    field[j][i] = 0;
                    break;
            }
        }
    }

    getline( config, line );
    deathsOfGreen = atoi( line.c_str() );

    getline( config, line );
    deathsOfRed = atoi( line.c_str() );

    getline( config, line );
    deathsOfDemons = atoi( line.c_str() );

    getline( config, line );
    shop->setMoney( atoi( line.c_str() ) );

    if( !hasPlayer ) player = 0;

    save.close();
    config.close();
}

void Field::clear() {
    for( int i = 0; i < WIDTH; i++ ){
        for( int j = 0; j < HEIGHT; j++ ){
            if( field[i][j] ){
                destroy( i, j );
                field[i][j] = 0;
            }
        }
    }

    update();
}


bool Field::move( int x, int y, Object* o ) {
     if( field[x][y] != 0 && (field[x][y]->getSymbol() == Wall::WALLCHAR ||
         field[x][y]->getSymbol() == Gangster::GANGSTERCHAR ||
         (!ifInBorders( x, y ) )  ||
         field[x][y]->getSymbol() == Bullet::BULLETCHAR ||
         field[x][y]->getSymbol() == BlackHole::BLACKHOLECHAR ) ) return false;

    int oldX = o->getX();
    int oldY = o->getY();

    if( (x == oldX && y == oldY) ||
         (!ifInBorders( oldX, oldY ) ) ) return false;
    if( field[x][y] ) delete field[x][y];

    field[x][y] = o;
    field[oldX][oldY] = 0;
    graph->paint( oldX, oldY, 0 );

    o->setX( x );
    o->setY( y );

    return true;
}

bool Field::move( Direction direction, int speed, Object* o ) {
    int x = o->getX();
    int y = o->getY();

    switch( direction ){
        case     NORTH : return move( x        , y - speed, o ); break;
        case NORTHEAST : return move( x + speed, y - speed, o ); break;
        case      EAST : return move( x + speed, y        , o ); break;
        case SOUTHEAST : return move( x + speed, y + speed, o ); break;
        case     SOUTH : return move( x        , y + speed, o ); break;
        case SOUTHWEST : return move( x - speed, y + speed, o );break;
        case      WEST : return move( x - speed, y        , o ); break;
        case NORTHWEST : return move( x - speed, y - speed, o ); break;
        default: return false; break;
    }
}

void Field::destroy( int x, int y ) {
    if( field[x][y] && ifInBorders( x, y ) ){
        if( player == field[x][y] ) player = 0;
        delete field[x][y];
        graph->deleteResourses( x, y );
        field[x][y] = 0;
        graph->paint( x, y, 0 );
    }
}

Object* Field::objectAt( int x, int y ) const {
    if( ifInBorders( x, y ) ) return field[x][y];
    else return 0;
}

Object* Field::objectAt( Direction d, int distance, Object* o ) {
    int x = o->getX(), y = o->getY();
    switch( d ){
        case     NORTH :                y -= distance; break;
        case NORTHEAST : x += distance; y -= distance; break;
        case      EAST : x += distance;                break;
        case SOUTHEAST : x += distance; y += distance; break;
        case     SOUTH :                y += distance; break;
        case SOUTHWEST : x -= distance; y += distance; break;
        case      WEST : x -= distance;                break;
        case NORTHWEST : x -= distance; y -= distance; break;
        default: return false; break;
    }

    if( ifInBorders( x, y ) ) return field[x][y];
    else return false;
}
Object* Field::objectAt( Direction d, int distance, int x, int y ) {
    switch( d ){
        case     NORTH :                y -= distance; break;
        case NORTHEAST : x += distance; y -= distance; break;
        case      EAST : x += distance;                break;
        case SOUTHEAST : x += distance; y += distance; break;
        case     SOUTH :                y += distance; break;
        case SOUTHWEST : x -= distance; y += distance; break;
        case      WEST : x -= distance;                break;
        case NORTHWEST : x -= distance; y -= distance; break;
        default: return false; break;
    }

    if( ifInBorders( x, y ) ) return field[x][y];
    else return false;
}

int Field::objectAtX(  Direction d, int distance, int x ) {
    switch( d ){
        case     NORTH :                break;
        case NORTHEAST : x += distance; break;
        case      EAST : x += distance; break;
        case SOUTHEAST : x += distance; break;
        case     SOUTH :                break;
        case SOUTHWEST : x -= distance; break;
        case      WEST : x -= distance; break;
        case NORTHWEST : x -= distance; break;
        default: return 0; break;
    }
    return x;
}

int Field::objectAtY(  Direction d, int distance, int y ) {
    switch( d ){
        case     NORTH : y -= distance; break;
        case NORTHEAST : y -= distance; break;
        case      EAST :                break;
        case SOUTHEAST : y += distance; break;
        case     SOUTH : y += distance; break;
        case SOUTHWEST : y += distance; break;
        case      WEST :                break;
        case NORTHWEST : y -= distance; break;
        default: return 0; break;
    }
    return y;
}

bool Field::enemyInDirection( Direction d, Mob* m ){
    int x = m->getX();
    int y = m->getY();
    int range = m->getSightRange();
    for( int i = 1; i < range; i++ ){
        Object* o = objectAt( d, i, m );
        if( !ifInBorders( x, y ) ) return false;
        if( o ){
            switch( (int)o->getSymbol() ){
                case( Bullet::BULLETCHAR ):                   break;
                case( Wall::WALLCHAR ):         return false; break;
                case( Gangster::GANGSTERCHAR ):
                        if( m->getTeam() != o->getTeam() ) return true;
                        else return false;
                        break;
                case( BlackHole::BLACKHOLECHAR ):
                        if( m->getTeam() != o->getTeam() ) return true;
                        else return false;
                default:                                      break;
            }
        }
    }
    return false;
}

Direction Field::enemyInSight( Mob* m ) {
    for( int i = 0; i < 8; i++ ){
        if( enemyInDirection( Direction ( i ), m ) ) return (Direction) i;
    }
    return NONE;
}

bool Field::dangerInDirection( Direction d, Mob* m ) {
    int x = m->getX();
    int y = m->getY();
    int range = m->getSightRange();
        for( int i = 1; i < range; i++ ){
            Object* o = objectAt( d, i, m );
            if( !ifInBorders( x, y ) ) return false;
            if( o ){
                switch( (int)o->getSymbol() ){
                    case( Bullet::BULLETCHAR ):
                        if( objectAt( o->getX(), o->getY() )->getDirection() ==
                            invertDirection( d ) )  return true;  break;
                    case( Wall::WALLCHAR ):         return false; break;
                    case( Gangster::GANGSTERCHAR ): return false; break;
                    default:                        return false; break;
                }
            }
        }
    return false;
}

Mob* Field::findShiftDirectional( Mob* m, Direction d ){
    int x = m->getX();
    int y = m->getY();
    int range = m->getSightRange();
        for( int i = 1; i < range; i++ ){
            Object* o = objectAt( d, i, m );
            if( !ifInBorders( x, y ) ) return false;
            if( o ){
                switch( (int)o->getSymbol() ){
                    case( Gangster::GANGSTERCHAR ):
                    if( dynamic_cast<Mob*>( o ) != player ) {
                        return dynamic_cast<Mob*>( o );
                    } else   break;
                    default: break;
                }
            }
        }
    return 0;
}

Mob* Field::findShift( Mob* m ){
    for( int i = 0; i < 8; i++ ){
        if( findShiftDirectional( m, Direction( i ) ) ) return findShiftDirectional( m, Direction( i ) );
    }
    return 0;
}

void Field::shiftSwap( Mob* m, Mob* l ){
    int health1 = m->getLifes(), health2 = l->getLifes();
    int speed1 = m->getMoveSpeed(), speed2 = l->getMoveSpeed();
    int x1 = m->getX(), x2 = l->getX();
    int y1 = m->getY(), y2 = l->getY();

    m->setLifes( health2 );
    m->setMoveSpeed( speed2 );

    l->setLifes( health1 );
    l->setMoveSpeed( speed1 );

    if( l->isPlayer() ) setPlayer( l );
    if( m->isPlayer() ) setPlayer( m );
    swap( field[x1][y1], field[x2][y2] );
    l->setX( x1 );
    l->setY( y1 );
    m->setX( x2 );
    m->setY( y2 );

    l->setUpdateStatus( true );
    m->setUpdateStatus( true );
}

bool Field::shift( Mob* m ){
    if( m->getShifts() <= 0 ) return false;
    Mob* s = findShift( m );
    if( s == 0 ) return false;
    shiftSwap( m, s );
    m->setShifts( m->getShifts() - 1 );
    return true;
}

Direction Field::dangerInSight( Mob* m ) {
    for( int i = 0; i < 8; i++ ){
        if( dangerInDirection( (Direction) i, m ) ) return (Direction) i;
    }
    return NONE;
}

void Field::resurrectPlayer( int x, int y ) {
    if( player != 0 || !ifInBorders( x, y ) ) return;
    else {
        if( field[x][y] != 0 ) destroy( x, y );
        player = new Gangster( x, y, this, true,
                               TEAMENUM,
                               new KeyboardController( 0,
                               graph->playerInput() ), 2,
                               3, false, true, 2, 0, 75 );
        field[x][y] = player;
        field[x][y]->paint();
    }
}

bool Field::spawnObject( int x, int y, Object* o ) {
    if( field[x][y] != 0 || !(ifInBorders( x, y ) ) || o == 0 ) return false;
    else{
        field[x][y] = o;
        return true;
    }
    return false;
}

bool Field::spawnObject( Direction d, int distance, Object* o ) {
    int x = o->getX(), y = o->getY();
    switch( d ){
        case     NORTH :                y -= distance; break;
        case NORTHEAST : x += distance; y -= distance; break;
        case      EAST : x += distance;                break;
        case SOUTHEAST : x += distance; y += distance; break;
        case     SOUTH :                y += distance; break;
        case SOUTHWEST : x -= distance; y += distance; break;
        case      WEST : x -= distance;                break;
        case NORTHWEST : x -= distance; y -= distance; break;
        default: return false; break;
    }

    if( ifInBorders( x, y ) ) return spawnObject( x, y, o );
    else return false;
}

void Field::generate( GenerationType type ) {
      // initializing random field generation
    switch( type ){
        case( DEFAULT   ):   generateDefault();         break;
        case( HUGEFIGHT ):   generateHugeFight();       break;
        case( PATHFINDING ): generatePathfindingTest(); break;
        default:             generateDefault();         break;
    }

}

void Field::generateDefault() {
    srand ( time( NULL ) );
    bool gotPlayer = false;
    int x = 2, y = 2;
    int rand1 = rand() % 10 + 2, rand2 = rand() % 10 + 2,
        rand3 = rand() % 15 + 7, rand4 = rand() % 15 + 7,
        rand5 = rand() % Field::WIDTH, rand6 = rand() % Field::HEIGHT;
    int wallChance = rand() % 95 + 5;
    for( int i = 0; i < WIDTH; i++ ) {
        for( int j = 0; j < HEIGHT; j++ ) {
            if( ifSpaceNearEdges( i, j ) ) {
                field[i][j] = new Wall( i, j, this, true );
            }
            else if( ifSpaceNearEdgeWalls( i, j ) ){
                field[i][j] = 0;
            }
            else if( ifCircle( i, j, x, y ) ) {
                if( rand() % 100 > wallChance ) field[i][j] = new Wall( i, j, this, true );
                else field[i][j] = 0;
            }
            else if( ifCircle( i, j, x * 4, y * 4 ) ) {
                if( rand() % 100 > 50 ) field[i][j] = new BlackHole( i, j, this,
                                                                     true, 5,
                                                                     60, 80, 10,
                                                                     randomTeam() );
                else field[i][j] = 0;
            }
            else if( ifCircle( i, j, x * rand3, y * rand4 ) ) {
                if( rand() % 100 > wallChance ) field[i][j] = new Wall( i, j, this, true );
                else field[i][j] = 0;
            }
            else if( ifCircle( i, j, x * rand1, y * rand2 ) ) {
                if( rand() % 100 > wallChance ) field[i][j] = new Wall( i, j, this, true );
                else field[i][j] = 0;
            }
            else if( ifCircle( i, j, x * 11, y * 11 ) ) {
                if( rand() % 100 > wallChance ) field[i][j] = new Wall( i, j, this, true );
                else field[i][j] = 0;
            }
            else if( ifCircle( i, j, x * 12, y * 12 ) ) {
                if( rand() % 100 > wallChance ) field[i][j] = new Wall( i, j, this, true );
                else field[i][j] = 0;
            }
            else if( ifCircle( i, j, x * 15, y * 15 ) ) {
                if( rand() % 100 > wallChance ) field[i][j] = new Wall( i, j, this, true );
                else field[i][j] = 0;
            }
            else if( ifCircle( i, j, x * 17, y * 17 ) ) {
                if( rand() % 100 > wallChance ) field[i][j] = new Wall( i, j, this, true );
                else field[i][j] = 0;
            }
            else if( i == rand5 && j == rand6 ) {
                field[i][j] = new BlackHole( i, j, this,  true, 5, 60,
                                             40, 7, randomTeam() );
            }else if( ifCircle( i, j, x * 18, y * 18 ) ) {
                if( rand() % 100 > 62 ) field[i][j] = new BlackHole( i, j, this,
                                                                     true, 5,
                                                                     60, 80, 7,
                                                                     randomTeam() );
                else field[i][j] = 0;
            }
            else if( ifLowerLeftQuarter( i, j ) || ifUpperLeftQuarter( i, j ) ) {
                if( rand() % 100 > 20 ) field[i][j] = 0;
                else{
                    if( rand() % 100 > 83 ){
                        if( !gotPlayer ){
                            player = new Gangster( i, j, this, true,
                                                   TEAMENUM,
                                                   new KeyboardController( 0,
                                                   graph->playerInput() ), 2,
                                                   3, false, true, 2, 0, 4 );
                            field[i][j] = player;
                            gotPlayer = true;
                        }
                        else field[i][j] = new Gangster( i, j, this, true,
                                                         TEAMENUM,
                                                         randController() );
                    } else field[i][j] = 0;
                }
            }
            else if( ifUpperRightQuarter( i, j ) || ( ifLowerRightQuarter( i, j ) ) ) {
                if( rand() % 100 > 20 ) field[i][j] = 0;
                else{
                    if( rand() % 100 > 55 ){
                        field[i][j] = new Gangster( i, j, this, true,
                                                    TEAMID,
                                                    randController() );
                    }else field[i][j] = 0;
                }
            }
            else{
                field[i][j] = 0;
            }
        }
    }
}

void Field::generateHugeFight(){
    srand ( time( NULL ) );
    bool gotPlayer = false;

    for( int i = 0; i < WIDTH; i++ ) {
        for( int j = 0; j < HEIGHT; j++ ) {
            if( ifSpaceNearEdges( i, j ) ){
                field[i][j] = new Wall( i, j, this, true );
            }
            else if( ifSpaceNearEdgeWalls( i, j ) ) {
                field[i][j] = 0;
            }
            else if( ifOuterCircle( i, j ) ) {
                if( rand() % 100 > 10 ) field[i][j] = new Wall( i, j, this, true );
                else field[i][j] = 0;
            }
            else if( ifUpperLeftQuarter( i, j ) || ifLowerRightQuarter( i, j ) ) {
                if( rand() % 100 > 2 ) field[i][j] = 0;
                else field[i][j] = new Wall( i, j, this, true );
            }
            else if( ifLowerLeftQuarter( i, j ) ) {
                if( rand() % 100 > 15 ) field[i][j] = 0;
                else{
                        if( !gotPlayer ){
                            player = new Gangster( i, j, this, true, TEAMENUM,
                                                   new KeyboardController( 0 ),
                                                   2, 3, false, true, false, 1, 2);
                            field[i][j] = player;
                            gotPlayer = true;
                        }
                        else field[i][j] = new Gangster( i, j, this, true,
                                                         TEAMENUM,
                                                         new RoamingGangster( 0 ) );
                }
            }
            else if( ifUpperRightQuarter( i, j ) ) {
                if( rand() % 100 > 15 ) field[i][j] = 0;
                else {
                    field[i][j] = new Gangster( i, j, this, true, TEAMID,
                                                new RoamingGangster( 0 ) );
                }
            }
            else{
                field[i][j] = 0;
            }
        }
    }
}

void Field::generatePathfindingTest() {
    srand ( time( NULL ) );
    bool gotPlayer = false;
    bool gotMob = false;

    for( int i = 0; i < WIDTH; i++ ) {
        for( int j = 0; j < HEIGHT; j++ ) {
            if( ifSpaceNearEdges( i, j ) ) {
                field[i][j] = new Wall( i, j, this, true );
            }
            else if( ifSpaceNearEdgeWalls( i, j ) ) {
                field[i][j] = 0;
            }
            else if( ifOuterCircle( i, j ) ) {
                if( rand() % 100 > 10 ) field[i][j] = new Wall( i, j, this, true );
                else field[i][j] = 0;
            }
            else if( ifUpperLeftQuarter( i, j ) || ifLowerRightQuarter( i, j ) ) {
                if( rand() % 100 > 2 ) field[i][j] = 0;
                else {
                    if( !gotMob ) {
                        field[i][j] = new Gangster( i, j, this, true, TEAMENUM,
                                                    new RoamingGangster( 0 ) );
                        gotMob = true;
                    }
                }
            }
            else if( ifLowerLeftQuarter( i, j ) ){
                if( rand() % 100 > 15 ) field[i][j] = 0;
                else{
                    if( !gotPlayer ) {
                        player = new Gangster( i, j, this, true, TEAMENUM,
                                               new KeyboardController( 0,
                                               graph->playerInput() ),
                                               2, 3000, false, true,
                                               1000, 0, 200 );
                        field[i][j] = player;
                        gotPlayer = true;
                    }
                }
            }
            field[i][j] = 0;
        }
    }
}

bool Field::ifInBorders( int x, int y ) const {
    return ( x < WIDTH && y < HEIGHT &&
             x >= 0 && y >= 0 );
}

bool Field::ifSpaceNearEdges( int i, int j ) const {
    return (i == 0 || j == 0 || i == WIDTH - 1 || j == HEIGHT - 1);
}

bool Field::ifSpaceNearEdgeWalls( int i, int j ) const {
    return ( (i == 1 || j == 1 || i == WIDTH - 2 || j == HEIGHT - 2)
              && i != 0 && j != 0
            && i != WIDTH - 1 && j != HEIGHT - 1 );
}

bool Field::ifOuterCircle( int i, int j ) const {
    return ( (i == 2 || j == 2 || i == WIDTH - 3 || j == HEIGHT - 3)
            && i > 1 && j > 1
            && j < HEIGHT - 2 && i < WIDTH - 2 );
}

bool Field::ifCircle( int i, int j, int x, int y ) const {
    return ( (i == x || j == y || i == WIDTH - x - 1 || j == HEIGHT - y - 1)
             && (i > x - 2) &&
             (j > y - 2) && (i < WIDTH - x + 1) && (j < HEIGHT - y + 1) );
}

bool Field::ifLowerRightQuarter( int i, int j ) const {
    return ( i > WIDTH / 2 && j > HEIGHT / 2 );
}

bool Field::ifUpperLeftQuarter( int i, int j ) const {
    return ( i < WIDTH / 2 && j < HEIGHT / 2 );
}

bool Field::ifUpperRightQuarter( int i, int j ) const {
    return ( i > WIDTH / 2 && j < HEIGHT / 2 );
}

bool Field::ifLowerLeftQuarter( int i, int j ) const {
    return ( i < WIDTH / 2 && j > HEIGHT / 2 );
}
